'use strict';

// 修改_request函数，使其返回Promise，方便使用async与await来进行异步操作。
var Odoo = function (config) {
  config = config || {};

  this.host = config.host;
  this.port = config.port || 80;
  this.database = config.database;
  this.username = config.username;
  this.password = config.password;
};

// Connect

Odoo.prototype.connect = function(){
  var params = {
    db: this.database,
    login: this.username,
    password: this.password
  };

  var json = JSON.stringify({ params: params });
  var url = 'http://' + this.host + ':' + this.port + '/web/session/authenticate';

  var options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Content-Length': json.length
    },
    body: json
  };
  return fetch(url, options)
    .then(res=>{
      this.sid = res.headers.map['set-cookie'][0].split(';')[0];
      console.log('sid:', this.sid);
      return res.json()
    })
    .then(data=>{
        this.uid = data.result.uid;
        this.session_id = data.result.session_id;
        this.context = data.result.user_context;
        this.username = data.result.username;
        return data.result
      });
};

// Search records
Odoo.prototype.search = function (model, params) {
  // assert(params.ids, "Must provide a list of IDs.");
  //assert(params.domain, "Must provide a search domain.");

  return this._request('/web/dataset/call_kw', {
    kwargs: {
      context: this.context
    },
    model: model,
    method: 'search',
    args: [
      params.domain,
    ],
  });
};

// Search & Read records
// https://www.odoo.com/documentation/8.0/api_integration.html#search-and-read
// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.search
// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.read
Odoo.prototype.search_read = function (model, params) {
  //assert(params.domain, "'domain' parameter required. Must provide a search domain.");
  //assert(params.limit, "'limit' parameter required. Must specify max. number of results to return.");

  return this._request('/web/dataset/call_kw', {
    model: model,
    method: 'search_read',
    args: [],
    kwargs: {
      context: this.context,
      domain: params.domain,
      offset: params.offset,
      limit: params.limit,
      order: params.order,
      fields: params.fields,
    },
  });
};

// Get record
// https://www.odoo.com/documentation/8.0/api_integration.html#read-records
// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.read
Odoo.prototype.get = function (model, params) {
  //assert(params.ids, "Must provide a list of IDs.");

  return this._request('/web/dataset/call_kw', {
    model: model,
    method: 'read',
    args: [
      params.ids,
    ],
    kwargs: {
      fields: params.fields,
    },
  });
}; //get


// Browse records by ID
// Not a direct implementation of Odoo RPC 'browse' but rather a workaround based on 'search_read'
// https://www.odoo.com/documentation/8.0/reference/orm.html#openerp.models.Model.browse
Odoo.prototype.browse_by_id = function(model, params) {
  params.domain = [['id', '>', '0' ]];  // assumes all records IDs are > 0
  return this.search_read(model, params);
}; //browse


// Create record
Odoo.prototype.create = function (model, params) {
  return this._request('/web/dataset/call_kw', {
    kwargs: {
      context: this.context
    },
    model: model,
    method: 'create',
    args: [params]
  });
};

// Update record
Odoo.prototype.update = function (model, id, params) {
  if (id) {
    return this._request('/web/dataset/call_kw', {
      kwargs: {
        context: this.context
      },
      model: model,
      method: 'write',
      args: [[id], params]
    });
  }
};

// Delete record
Odoo.prototype.delete = function (model, id) {
  return this._request('/web/dataset/call_kw', {
    kwargs: {
      context: this.context
    },
    model: model,
    method: 'unlink',
    args: [[id]]
  });
};


// Generic RPC wrapper
// DOES NOT AUTO-INCLUDE context
Odoo.prototype.rpc_call = function (endpoint, params) {
  //assert(params.model);
  // assert(params.method);
  // assert(params.args);
  // assert(params.kwargs);
  // assert(params.kwargs.context);

  return this._request(endpoint, params);
}; //generic

Odoo.prototype.json_rpc = function (method, model, args) {
  console.log(this);
  const endpoint = '/jsonrpc'
  const params = {
    service: 'object',
    method:'execute',
    args:[ this.database, this.uid, this.password, model, method, args]
  }
  return this.rpc_call(endpoint, params)
};


// Private functions
Odoo.prototype._request = function (path, params) {
  params = params || {};
  const body = {
    jsonrpc: '2.0',
    id: new Date().getUTCMilliseconds(),
    method: 'call',
    params: params
  }
  var url = 'http://' + this.host + ':' + this.port + (path || '/') + '';
  var options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Cookie': this.sid + ';'
    },
    body: JSON.stringify(body)
  };

  return fetch(url, options)
};

module.exports = Odoo;
